#include "Wireless.h"
#include "SX127X.h"
#include "Sys.h"
#include "ChannelScan.h"

#define WIRELESS_CONNECT_TIMEOUT 2000
#define WIRELESS_PROTO_HEAD 0x5CB5
#define WIRELESS_PROTO_VERSION 0x01
#define WIRELESS_SYNCHRONOUS_WORD 0x231236
#define MHz(x) (x * 1000000)

#pragma pack(1)
typedef struct
{
    uint16_t head;
    uint32_t addr;
    uint8_t version;
    uint8_t device;
    uint8_t cmd;
    uint8_t data[];
} WirelessProto_t;
#pragma pack()

extern SPI_HandleTypeDef hspi3;

static WirelessDataRecv_f g_recvHandle;
static SX127X_t g_sx1276Config;
static SysTime_t gRecvTime = 0;
static uint8_t gChannel;
static uint8_t gRSSI;

void WirelessSendData(WirelessCmd_t cmd, uint8_t *data, uint16_t length)
{
    static uint8_t buff[60];
    uint32_t i = 0;
    WirelessProto_t *proto = (WirelessProto_t *)buff;

    if (SysWirelessAddress() != SYS_WIRELESS_BRAODCAST_ADDRESS)
    {
        proto->head = WIRELESS_PROTO_HEAD;
        proto->version = WIRELESS_PROTO_VERSION;
        proto->addr = SysWirelessAddress();
        proto->device = SysDeviceType();
        proto->cmd = cmd;
        memcpy(proto->data, data, length);
        FSK_Transmit(&g_sx1276Config, buff, sizeof(WirelessProto_t) + length);
        while (!FSK_CheckPackSent(&g_sx1276Config))
        {
            i++;
            if (i > 0xffff)
            {
                break;
            }
        }
    }
}

static void updateRSSI(uint8_t *rssi, uint8_t num)
{
    uint8_t min = 0xff;
    uint8_t max = 0;
    uint16_t sum = 0;
    uint8_t i;

    for (i = 0; i < num; i++)
    {
        sum += rssi[i];
        if (min > rssi[i])
        {
            min = rssi[i];
        }
        if (max < rssi[i])
        {
            max = rssi[i];
        }
    }
    gRSSI = (sum - min - max) / (num - 2);
}

static void wirelessDataHandle(void)
{
    uint8_t recvBuff[60] = {0};
    char crcerror = false;
    uint8_t packleght = 0;
    WirelessProto_t *proto;
    static uint8_t rssi[12];
    static uint8_t rid = 0;

    SX127X_set_op_mode(&g_sx1276Config, RX);

    if (FSK_CheckPreambleDetect(&g_sx1276Config))
    {
        FSK_get_packet_rssi(&g_sx1276Config, &rssi[rid++]);
        if (rid >= sizeof(rssi))
        {
            updateRSSI(rssi, sizeof(rssi));
            rid = 0;
        }
    }

    if (FSK_CheckPayloadReady(&g_sx1276Config))
    {
        // FSK_get_packet_rssi(&g_sx1276Config, &gRSSI);
        FSK_ReadPacket(&g_sx1276Config, recvBuff, sizeof(recvBuff), &packleght, &crcerror);
        if (!crcerror && g_recvHandle != NULL)
        {
            proto = (WirelessProto_t *)recvBuff;
            if (proto->head == WIRELESS_PROTO_HEAD)
            {
                ChannelScanStop();
                if (proto->addr == SysWirelessAddress() && proto->device == SysDeviceType())
                {
                    g_recvHandle(proto->cmd, proto->version, proto->data, packleght - sizeof(WirelessProto_t));
                }
                else
                {
                    if (SysWirelessAddress() == SYS_WIRELESS_BRAODCAST_ADDRESS && proto->device == SysDeviceType())
                    {
                        SysWirelessAddressSet(proto->addr);
                    }
                }
                gRecvTime = SysTime();
            }
        }
    }

    if (SysTimeHasPast(gRecvTime, WIRELESS_CONNECT_TIMEOUT))
    {
        if (!ChannelScanIsStart())
        {
            ChannelScanStart(CHANNEL_SCAN_CHANNEL_COUNT / 2);
        }
    }
}

static void setChannel(uint8_t ch, int freq)
{
    sysLog("switch channel: %d\r\n", ch);
    SX127X_set_frequency(&g_sx1276Config, freq);
    gChannel = ch;
}

bool WirelessDisconnect(void)
{
    if (gRecvTime == 0 || SysTimeHasPast(gRecvTime, WIRELESS_CONNECT_TIMEOUT))
    {
        return true;
    }
    return false;
}

uint8_t WirelessRSSI(void)
{
    if (WirelessDisconnect())
    {
        return 99;
    }
    return gRSSI;
}

uint8_t WirelessChannel(void)
{
    return gChannel;
}

void WirelessPoll(void)
{
    wirelessDataHandle();
    ChannelScanPoll();
}

void WirelessInitialize(WirelessDataRecv_f recvHandle)
{
    g_sx1276Config.spi_bus = hspi3;
    g_sx1276Config.reset_gpio_port = GPIOD;
    g_sx1276Config.reset_pin = GPIO_PIN_2;
    g_sx1276Config.ss_gpio_port = GPIOA;
    g_sx1276Config.ss_pin = GPIO_PIN_15;

    g_sx1276Config.Current_Modulation = FSK_Modulation; // FSK调制
    g_sx1276Config.Current_Op_Mode = STANDBY;           // 随意
    g_sx1276Config.Frequency = MHz(476);                // 设置载波频率
    g_sx1276Config.PaRampTime = PaRampTime_40_us;       // FSK 模式下斜升/斜降时间
    g_sx1276Config.LnaGain = LnaGainG1;                 // 接收机增益设置 最大
    g_sx1276Config.LnaBoost = 0;
    g_sx1276Config.PaSelect = PA_BOOST_Pin;                         // 设置输出引脚
    g_sx1276Config.TxPower = 20;                                    // 设置发射功率
    g_sx1276Config.FSK_Config.FrequencyDeviation = 25e3;            // 设置频率偏移   但频率偏差必须设定在600Hz-200kHz之间。 FreqDev +Bitrate/2 <= 250 kHz。
    g_sx1276Config.FSK_Config.Bitrate = FSK_BITRATE_25_KBPS;        // 设置比特率 通信比特率不能超过单边接收机带宽的两倍
    g_sx1276Config.FSK_Config.PreambleLength = 12;                  // 前导码的长度  前导码长度设置比较特殊，接收端配置的前导码长度必须大于等于发送端的前导码长度，接收端才能接收
                                                                    // 到数据，这就是基于前导码长度的数据包过滤，默认长度为 8 个字节，最小可以设置 6 个字节
    g_sx1276Config.FSK_Config.PreamblePolarity = Polarity_AA;       // 前导码的极性
    g_sx1276Config.FSK_Config.SyncWordGeneration = 1;               // 是否打开同步字
    g_sx1276Config.FSK_Config.SyncWord = WIRELESS_SYNCHRONOUS_WORD; // 同步字
    g_sx1276Config.FSK_Config.SyncWordSize = 3;                     // 同步字的长度设置(Byte)
    g_sx1276Config.FSK_Config.PacketFormat = VariableLength;        // 设置数据包的格式为可变的
    g_sx1276Config.FSK_Config.DataProcessingMode = PacketMode;      // 设置数据处理模式为数据包模式
    g_sx1276Config.FSK_Config.PayloadLength = 255;                  // 如果数据处理模式为数据包模式 是 RX模式下最大长度 否则是负载长度
    g_sx1276Config.FSK_Config.CrcCalculation = 1;                   // 打开CRC校验
    g_sx1276Config.FSK_Config.CrcWhitenningType = CCITT_CRC;        // CRC类型
    g_sx1276Config.FSK_Config.CrcAutoclear = true;
    g_sx1276Config.FSK_Config.Encoding = Whitenning;                     // DC 消除编码/解码 Whitenning和CCITT_CRC 一对
    g_sx1276Config.FSK_Config.DataShaping = FSK_NoShaping;               // 数据整形
    g_sx1276Config.FSK_Config.AutoRestartRX = AutorestartRX_On_PLL_Lock; // 接收到有效数据包后控制接收机的自动重启

    // 接收机配置
    g_sx1276Config.FSK_Config.RxBandwidth = 60e3;      // 设置接收带宽(Hz)
    g_sx1276Config.FSK_Config.AfcBandwidth = 83.333e3; // 设置AFC(Hz)
    g_sx1276Config.FSK_Config.PreambleDetectorOn = 1;  // 前导码检测开/关
    // g_sx1276_init.FSK_Config.PreambleDetectorSize = ;              //触发中断所需检测到的前导码字节数(default 0x01)
    // g_sx1276_init.FSK_Config.PreambleDetectorTolerance = ;         //可以容忍的码片误差数量每比特 4 码片(default 0x0A)
    g_sx1276Config.FSK_Config.RssiOffset = RssiSmoothing_64_Samples; // 定义计算 RSSI 平均值所用的采样次数
    // g_sx1276_init.DioMapping1 = ;
    // g_sx1276_init.DioMapping2 = ;

    if (FSK_init(&g_sx1276Config) != HAL_OK)
    {
        // REMOTE_INFO("FSK_INIT ERROR");
    }

    if (SX127X_Config(&g_sx1276Config) != HAL_OK)
    {
        // REMOTE_INFO("SX127X_Config ERROR");
    }

    ChannelScanInitialize(setChannel);
    ChannelScanStart(CHANNEL_SCAN_CHANNEL_COUNT / 2);
    g_recvHandle = recvHandle;
    gRecvTime = SysTime();
}
